package com.cskaoyan.javase.oop2._1extends._9override._0introduction;

/**
 * 实际开发中,"对象名.成员变量名"是非常少见的
 * 因为开发中的成员变量,多数是私有化的,直接对象名点访问是做不到的
 * 而"对象名.成员方法"是开发中最常见的使用对象的方式
 * 它更重要的,在这一小节,我们来研究"对象名.成员方法名"的调用机制.
 *
 * 在上一节一样，父子类中的成员方法也是可以同名的。
 * 那么我们直接创建子类对象，使用子类引用接收。
 * 调用同名方法，会发现访问的结果是子类中方法的行为
 * 那么父类中的那个同名成员方法去哪了呢？还能够调用吗?
 *
 * 首先它肯定是存在的，方法不过是方法区的二进制指令合集罢了，类加载时期，装载进方法区，不会物理消失。
 * 那么尝试用父类方法的"Getter"方法来调用父类同名方法,发现失败了
 * 这说明只要用子类对象调用这个同名方法,无论在哪里调用,结果都是子类的行为
 * 这种现象称之为"方法的覆盖"
 * 当然"方法的覆盖"仍然是因为"对象名.成员方法名"的特殊的调用机制决定的
 * 我们仍然可以在子类中用super关键字去调用父类同名成员方法.
 *
 * 接下来我们重点研究"对象名.成员方法"的调用机制,仍然是两个角度:
 *      1.调用方法的范围
 *      2.调用方法的执行结果
 * 在存在继承父子类的前提下,创建对象的方式有三种:
 *      1.创建父类对象,用父类引用接收
 *      2.创建子类对象,用子类引用接收
 *      3.创建子类对象,用父类引用接收
 *
 * 首先访问范围仍然是编译概念,和"对象名.成员变量名"没有区别,都是由引用的数据类型来决定的
 *
 * 重点看"对象名.成员方法"方法调用,的结果:
 * 通过测试,我们发现:
 *      "对象名.成员方法"方法调用的结果
 *      要根据对象的具体类型来决定
 *      如果在对象的类型中,存在该方法的实现
 *      那么就一定体现为对象类型中的行为
 *
 * 最后总结:
 * 综合对象名点访问成员方法的范围和结果，发现：
 *      1.访问范围仍然是要靠 引用的数据类型 来决定。
 *      2.但是方法的调用结果，就需要考虑对象的具体类型，是何种对象，就体现出它的行为。
 *
 *
 * @since 14:38
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*Son s = new Son();
        s.test();
        s.invokeFatherTest();
        s.superInvokeFatherTest();*/

        // 1.创建父类对象,用父类引用接收
        Father f = new Father();
        f.test();
        // 2.创建子类对象,用子类引用接收
        Son s = new Son();
        s.test();

        // 3.创建子类对象,用父类引用接收
        Father fs = new Son();
        fs.test();
        // ((Son) fs).sonOnly();
    }
}

class Father {
    public void test() {
        System.out.println("father");
    }
    // 父类独有的方法
    public void fatherOnly() {
        System.out.println("father only");
    }
    // 类比于Getter方法,写一个父类方法的"Getter"方法
    /*public void invokeFatherTest(){
        test();
    }*/
}

class Son extends Father {
    public void test() {
        System.out.println("son");
    }
    // 子类独有的方法
    public void sonOnly() {
        System.out.println("son only");
    }
    /*public void superInvokeFatherTest(){
        super.test();
    }*/
}